package system

import (
	"context"
	"fmt"
	"github.com/dustin/go-humanize"
	"github.com/gogf/gf/v2"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gcron"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/shirou/gopsutil/net"
	"github.com/shirou/gopsutil/v4/cpu"
	"github.com/shirou/gopsutil/v4/disk"
	"github.com/shirou/gopsutil/v4/host"
	"github.com/shirou/gopsutil/v4/load"
	"github.com/shirou/gopsutil/v4/mem"
	"github.com/shirou/gopsutil/v4/process"
	"os"
	"runtime"
	"runtime/debug"
	"server/internal/consts"
	"server/internal/model"
	"server/internal/service"
	"sync"
	"time"
)

type sSystemMonitor struct {
	data *model.SystemMonitorData
	sync.Mutex
	loadStartMonitorOnce sync.Once
}

func init() {
	service.RegisterSystemMonitor(&sSystemMonitor{
		data: new(model.SystemMonitorData),
	})
}

// StartMonitor 服务器监控数据统计
func (s *sSystemMonitor) StartMonitor(ctx context.Context) {
	s.loadStartMonitorOnce.Do(func() {
		s.data.StartTime = gtime.Now().String()
		_, err := gcron.AddSingleton(ctx, "*/10 * * * * *", func(ctx context.Context) {
			s.Lock()
			defer s.Unlock()

			// 统计系统负载
			s.loadAvg()

			// 统计流量
			s.loadNet()
		})
		if err != nil {
			g.Log().Error(gctx.GetInitCtx(), err)
		}
	})
}

// 统计网卡流量信息
func (s *sSystemMonitor) loadNet() {
	ios, _ := net.IOCounters(true)
	counter := new(model.SystemMonitorNet)
	counter.T = gtime.Now()

	// 汇总所有的io发送和接受总数
	for _, io := range ios {
		counter.BytesSend += io.BytesSent
		counter.BytesReceive += io.BytesRecv
	}
	// 对比上次统计的数据，计算上传和下载速率
	if len(s.data.Net) > 0 {
		lastCounter := s.data.Net[len(s.data.Net)-1]
		subSecond := counter.T.Sub(lastCounter.T).Seconds()
		counter.ReceiveAvg = uint64(float64(counter.BytesReceive-lastCounter.BytesReceive) / subSecond) // 时间段内的平均下载流量
		counter.SendAvg = uint64(float64(counter.BytesSend-lastCounter.BytesSend) / subSecond)          // 时间段内的平均上传流量
	}
	s.data.Net = append(s.data.Net, counter)
	maxLen := 180
	if len(s.data.Net) > maxLen {
		s.data.Net = s.data.Net[1:] // 舍弃切片第一个元素
	}
}

// loadAvg 统计系统负载，将获取到的负载数据记录
func (s *sSystemMonitor) loadAvg() {
	stat, err := load.Avg()
	if err != nil {
		g.Log().Error(gctx.GetInitCtx(), err)
		return
	}
	item := model.SystemMonitorLoadAvg{
		T:       gtime.Now(),
		LoadAvg: stat.Load1, // 过去1分钟的平均负载，linux是直接读取文件/proc/loadavg
	}
	s.data.LoadAvg = append(s.data.LoadAvg, &item)
	// 切片中只保留最近的数据，定时任务 10秒钟统计一次，保留半小时，60/10*30=180 可根据监控的定时任务频率进行调整
	maxLen := 180
	if len(s.data.LoadAvg) > maxLen {
		s.data.LoadAvg = s.data.LoadAvg[1:]
	}
}

// MonitorInfo 系统监控相关数据
func (s *sSystemMonitor) MonitorInfo() interface{} {
	return g.Map{
		"systemInfo": s.SystemInfo(),
		"hostInfo":   s.HostInfo(),
		"cpuInfo":    s.CpuInfo(),
		"memoryInfo": s.MemoryInfo(),
		"diskInfo":   s.DiskInfo(),
		"systemLoad": s.SystemLoad(),
		"netIoInfo":  s.GetNetIoInfo(),
	}
}

// ProcessInfo 系统进程，比较耗时，不建议频繁统计
func (s *sSystemMonitor) ProcessInfo() interface{} {
	data := make([]g.Map, 0, 10)
	processItems, err := process.Processes()
	if err != nil {
		return data
	}
	for _, item := range processItems {
		processItem := s.formatProcessInfo(item)
		//children, _ := item.Children()
		//childItems := make([]g.Map, 0)
		//for _, childItem := range children {
		//	childItems = append(childItems, s.formatProcessInfo(childItem))
		//}
		//processItem["children"] = childItems
		data = append(data, processItem)
	}

	return data
}

func (s *sSystemMonitor) formatProcessInfo(item *process.Process) g.Map {
	name, _ := item.Name()
	createTime, _ := item.CreateTime()
	createTimeDesc := ""
	if createTime > 0 {
		createTimeDesc = time.UnixMilli(createTime).Format(time.DateTime)
	}
	username, _ := item.Username()
	isRunning, _ := item.IsRunning()
	memoryPercent, _ := item.MemoryPercent()
	cpuPercent, _ := item.CPUPercent()
	return g.Map{
		"pid":           item.Pid,
		"username":      username,
		"name":          name,
		"createTime":    createTimeDesc,
		"isRunning":     isRunning,
		"memoryPercent": fmt.Sprintf("%.4f", memoryPercent*100) + "%",
		"cpuPercent":    fmt.Sprintf("%.4f", cpuPercent*100) + "%",
	}
}

// SystemInfo 系统运行相关指标
func (s *sSystemMonitor) SystemInfo() interface{} {
	// os 相关数据
	hostname, _ := os.Hostname()
	runDirectory, _ := os.Getwd()

	data := make([]model.SystemMonitorItem, 0, 10)
	data = append(data,
		model.SystemMonitorItem{Label: "Go版本", Value: runtime.Version()},
		model.SystemMonitorItem{Label: "GoFrame版本", Value: gf.VERSION},
		model.SystemMonitorItem{Label: "系统版本", Value: consts.VersionApp},
		model.SystemMonitorItem{Label: "Go的根目录", Value: runtime.GOROOT()},
		model.SystemMonitorItem{Label: "工作目录的根路径", Value: runDirectory},
		model.SystemMonitorItem{Label: "内核提供的主机名", Value: hostname},
		model.SystemMonitorItem{Label: "调用者的有效用户ID", Value: os.Geteuid()},
		model.SystemMonitorItem{Label: "调用者的组ID", Value: os.Getgid()},
		model.SystemMonitorItem{Label: "调用者的有效组ID", Value: os.Getegid()},
	)
	return data
}

// HostInfo 服务器基本信息相关指标
func (s *sSystemMonitor) HostInfo() interface{} {
	// 主机相关信息
	hostInfo, _ := host.Info()

	data := make([]model.SystemMonitorItem, 0, 10)
	data = append(data,
		model.SystemMonitorItem{Label: "主机名称", Value: hostInfo.Hostname},
		model.SystemMonitorItem{Label: "Uptime", Value: hostInfo.Uptime},
		model.SystemMonitorItem{Label: "主机开机时间", Value: time.Unix(int64(hostInfo.BootTime), 0).Format(time.DateTime)}, //返回主机开机时间的时间戳
		model.SystemMonitorItem{Label: "进程数", Value: hostInfo.Procs},
		model.SystemMonitorItem{Label: "OS", Value: hostInfo.OS},
		model.SystemMonitorItem{Label: "Platform", Value: hostInfo.Platform},
		model.SystemMonitorItem{Label: "PlatformFamily", Value: hostInfo.PlatformFamily},
		model.SystemMonitorItem{Label: "PlatformVersion", Value: hostInfo.PlatformVersion},
		model.SystemMonitorItem{Label: "KernelVersion", Value: hostInfo.KernelVersion},
		model.SystemMonitorItem{Label: "KernelArch", Value: hostInfo.KernelArch},
		model.SystemMonitorItem{Label: "VirtualizationSystem", Value: hostInfo.VirtualizationSystem},
		model.SystemMonitorItem{Label: "VirtualizationRole", Value: hostInfo.VirtualizationRole},
		model.SystemMonitorItem{Label: "HostID", Value: hostInfo.HostID},
	)
	return data
}

// SystemLoad 系统负载相关指标
func (s *sSystemMonitor) SystemLoad() interface{} {
	s.Lock()
	defer s.Unlock()

	data := s.data.LoadAvg
	for key, item := range data {
		data[key].TimeDesc = item.T.Time.Format(time.TimeOnly)
	}
	return data
}

// GetNetIoInfo 系统流量相关指标
func (s *sSystemMonitor) GetNetIoInfo() interface{} {
	s.Lock()
	defer s.Unlock()

	data := s.data.Net
	for key, item := range data {
		data[key].SendAvgDesc = humanize.Bytes(item.SendAvg)
		data[key].ReceiveAvgDesc = humanize.Bytes(item.ReceiveAvg)
		data[key].TimeDesc = item.T.Time.Format(time.TimeOnly)
	}
	return data
}

// CpuInfo CPU使用情况
func (s *sSystemMonitor) CpuInfo() interface{} {
	// cpu每秒使用率
	secondUsePercent, _ := cpu.Percent(time.Duration(time.Second), false)

	// cpu逻辑总数
	cpuLogicalTotal, _ := cpu.Counts(true)
	// cpu物理总数
	cpuPhysicalTotal, _ := cpu.Counts(false)

	return g.Map{
		"cpus": g.Map{
			"logical":  cpuLogicalTotal,
			"physical": cpuPhysicalTotal,
		},
		"usePercent": fmt.Sprintf("%.4f", secondUsePercent[0]),
	}
}

// MemoryInfo 获取内存使用率
func (s *sSystemMonitor) MemoryInfo() interface{} {
	memStat, _ := mem.VirtualMemory()
	memoryInfo := g.Map{
		"total":      humanize.Bytes(memStat.Total),
		"free":       humanize.Bytes(memStat.Free),
		"usePercent": fmt.Sprintf("%.4f", memStat.UsedPercent),
	}
	return memoryInfo
}

// DiskInfo 磁盘使用情况
func (s *sSystemMonitor) DiskInfo() interface{} {
	disks, _ := disk.Partitions(true) //所有分区
	total := uint64(0)
	free := uint64(0)
	used := uint64(0)
	for _, item := range disks {
		usage, _ := disk.Usage(item.Device)
		total += usage.Total
		free += usage.Free
		used += usage.Used
	}
	usePercent := (float64(used) / float64(total)) * 100
	return g.Map{
		"total":      humanize.Bytes(total),
		"free":       humanize.Bytes(free),
		"used":       humanize.Bytes(used),
		"usePercent": fmt.Sprintf("%.4f", usePercent),
	}
}

func (s *sSystemMonitor) GcInfo(ctx context.Context) (data interface{}) {
	//GC 信息
	memStats := &runtime.MemStats{}
	runtime.ReadMemStats(memStats)
	gCStats := &debug.GCStats{}
	debug.ReadGCStats(gCStats)

	data = g.Map{
		"memStats": g.Map{
			// 一般统计
			"Alloc":      memStats.Alloc,      // 已申请且仍在使用的字节数
			"TotalAlloc": memStats.TotalAlloc, // 已申请的总字节数（已释放的部分也算在内）
			"Sys":        memStats.Sys,        // 从系统中获取的字节数（下面XxxSys之和）
			"Lookups":    memStats.Lookups,    // 指针查找的次数
			"Mallocs":    memStats.Mallocs,    // 申请内存的次数
			"Frees":      memStats.Frees,      // 释放内存的次数

			// 主分配堆统计
			"HeapAlloc":    memStats.HeapAlloc,    // 已申请且仍在使用的字节数
			"HeapSys":      memStats.HeapSys,      // 从系统中获取的字节数
			"HeapIdle":     memStats.HeapIdle,     // 闲置span中的字节数
			"HeapInuse":    memStats.HeapInuse,    // 非闲置span中的字节数
			"HeapReleased": memStats.HeapReleased, // 释放到系统的字节数
			"HeapObjects":  memStats.HeapObjects,  // 已分配对象的总个数

			// L低层次、大小固定的结构体分配器统计，Inuse为正在使用的字节数，Sys为从系统获取的字节数
			"StackInuse":  memStats.StackInuse, // 引导程序的堆栈
			"StackSys":    memStats.StackSys,
			"MSpanInuse":  memStats.MSpanInuse, // mspan结构体
			"MSpanSys":    memStats.MSpanSys,
			"MCacheInuse": memStats.MCacheInuse, // mcache结构体
			"MCacheSys":   memStats.MCacheSys,
			"BuckHashSys": memStats.BuckHashSys, // profile桶散列表
			"GCSys":       memStats.GCSys,
			"OtherSys":    memStats.OtherSys,

			// 垃圾收集器统计
			"NextGC":        memStats.NextGC, // 会在HeapAlloc字段到达该值（字节数）时运行下次GC
			"LastGC":        memStats.LastGC, // 上次运行的绝对时间（纳秒）
			"PauseTotalNs":  memStats.PauseTotalNs,
			"PauseNs":       memStats.PauseNs, // 近期GC暂停时间的循环缓冲，最近一次在[(NumGC+255)%256]
			"NumGC":         memStats.NumGC,
			"NumForcedGC":   memStats.NumForcedGC,
			"GCCPUFraction": memStats.GCCPUFraction,
			"EnableGC":      memStats.EnableGC,
			"DebugGC":       memStats.DebugGC,
		},
		"GCStats": g.Map{
			"LastGC":         gCStats.LastGC,
			"NumGC":          gCStats.NumGC,
			"PauseTotal":     gCStats.PauseTotal,
			"Pause":          gCStats.Pause,
			"PauseEnd":       gCStats.PauseEnd,
			"PauseQuantiles": gCStats.PauseQuantiles,
		},
	}
	return data
}
